/*
 * @(#)WebdavFileStore.java
 *
 * Copyright (c) 2004 DCIVision Ltd
 * All rights reserved.
 *
 * This software is the confidential and proprietary information of DCIVision
 * Ltd ("Confidential Information").  You shall not disclose such Confidential
 * Information and shall use it only in accordance with the terms of the license
 * agreement you entered into with DCIVision Ltd.
 */
package com.dcivision.webdav;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URLDecoder;
import java.security.Principal;
import java.util.ArrayList;
import java.util.Date;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.StringTokenizer;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.commons.transaction.util.LoggerFacade;
import org.apache.slide.common.Service;
import org.apache.slide.common.ServiceAccessException;
import org.apache.slide.common.ServiceParameterErrorException;
import org.apache.slide.common.ServiceParameterMissingException;
import org.apache.slide.common.SlideException;
import org.apache.slide.security.AccessDeniedException;
import org.apache.slide.simple.store.BasicWebdavStore;
import org.apache.slide.simple.store.WebdavStoreBulkPropertyExtension;
import org.apache.slide.simple.store.WebdavStoreLockExtension;
import org.apache.slide.simple.store.WebdavStoreMacroCopyExtension;
import org.apache.slide.simple.store.WebdavStoreMacroDeleteExtension;
import org.apache.slide.simple.store.WebdavStoreMacroMoveExtension;
import org.apache.slide.store.util.FileHelper;
import org.apache.slide.structure.ObjectAlreadyExistsException;
import org.apache.slide.structure.ObjectNotFoundException;
import org.apache.slide.webdav.ActionContext;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;

import com.dcivision.dms.core.WebdavOperationManager;
import com.dcivision.framework.ApplicationException;
import com.dcivision.framework.DataSourceFactory;
import com.dcivision.framework.ErrorConstant;
import com.dcivision.framework.GlobalConstant;
import com.dcivision.framework.SessionContainer;
import com.dcivision.framework.web.LoginAction;
import com.dcivision.framework.web.LoginForm;
import com.dcivision.user.bean.UserRecord;

/**
 * <p>Class Name:       WebdavFileStore.java    </p>
 * <p>Description:      Webdave file store .</p>
 * @author              Beyond Qu
 * @company             DCIVision Limited
 * @creation date       19/11/2004
 * @version             $Revision: 1.19.2.8 $
 */

public class WebdavFileStore implements BasicWebdavStore, WebdavStoreLockExtension, WebdavStoreBulkPropertyExtension,
WebdavStoreMacroCopyExtension, WebdavStoreMacroMoveExtension, WebdavStoreMacroDeleteExtension {
  
  private static final Log log = LogFactory.getLog(WebdavFileStore.class);
  
  private static final String ROOTPATH_PARAMETER = "rootpath";
  
  private static final String LOCK_FILE_EXTENSION = ".lck";
  
  private static final String PROPERTY_FILE_PREFIX = ".";
  
  private static void save(InputStream is, File file) throws IOException {
    OutputStream os = new BufferedOutputStream(new FileOutputStream(file));
    try {
      FileHelper.copy(is, os);
    } finally {
      try {
        is.close();
      } finally {
        os.close();
      }
    }
  }
  
  private static File root = null;
  
  private static Service service = null;
  
  private static LoggerFacade logger = null;
  
  private WebdavOperationManager webdavOperationManager = null;
  
  private SessionContainer sessionCner=null;
  
  private UserRecord sessionUser=null;        
  
  private HttpServletRequest request=null;
  private HttpServletResponse response=null;     
  private String H_DESTINATION = "Destination";    
  private String sourceUri ="";
  private String destinationUri ="";    
  private String MOVE_METHED_NAME  ="MOVE";    
  private String COPY_METHED_NAME ="COPY";      
  
  private String SHORTCUT_EXTENSION =".lnk";      
 
  private void loginLogic(UserRecord user){
    
    
    ActionForward result=null;
    java.sql.Connection conn = null;
    
    
    try{            
      //getRequstAndSession();
      
      if(sessionUser==null||!(sessionUser.getLoginName().equals(user.getLoginName()))){
        try {
          conn = DataSourceFactory.getConnection();
          request.setAttribute(GlobalConstant.DB_KEY, conn);
        } catch (Exception e) {
          log.error(e, e);
          try {conn.close(); }catch (Exception ignore) {} finally { conn = null; } throw new ApplicationException(ErrorConstant.DB_GET_CONN_ERROR, e);
        }
        
        ActionMapping actionMapping=new ActionMapping();
        LoginAction loginAction=new LoginAction();
        LoginForm loginForm =new LoginForm();       
        ActionForward forwardConfig=null;
        
        forwardConfig=new ActionForward("LOGIN","/LOGIN",false);
        actionMapping.addForwardConfig(forwardConfig);
        
        forwardConfig=new ActionForward("HOME","/HOME",false);
        actionMapping.addForwardConfig(forwardConfig);
        
        forwardConfig=new ActionForward("CHG_PWD","/CHG_PWD",false);
        actionMapping.addForwardConfig(forwardConfig);       
        
        forwardConfig=null;
        
        loginForm.setAction("login");
        loginForm.setLoginName(user.getLoginName());         
        loginForm.setLoginPwd(user.getLoginPwd());       
        
        result=loginAction.execute(actionMapping,loginForm,request,response);
        try { conn.close();  }catch (Exception ignore) {}finally { conn = null; }
        try { request.removeAttribute(GlobalConstant.DB_KEY); }catch (Exception ignore) {} }
    }catch(ServletException e){
      try { conn.close();  }catch (Exception ignore) { }finally { conn = null;  }
      try { request.removeAttribute(GlobalConstant.DB_KEY); }catch (Exception ignore) {}
      log.error(e, e);
    }catch(Exception e){
      log.error(e, e);            
    }           
    if(result!=null){
      // get sessionContainer from request again.  -- must do it.
    }                       
  }
  
  public synchronized void begin(Service service, Principal principal, Object connection, LoggerFacade logger,
      Hashtable parameters) throws ServiceAccessException, ServiceParameterErrorException,
      ServiceParameterMissingException {
    // set parameters only once...
    if(null==request){
      getRequstAndSession();
    }
    if(null == connection && null != request ){
      UserRecord authUser=(UserRecord)request.getAttribute("AuthUserRecord");
      if(null != authUser){
        connection=authUser;
      }
    }
    /*
    if(connection instanceof UserRecord){
      loginLogic((UserRecord)connection);
    }
    */
  }
  
  
  public void commit() throws ServiceAccessException {
    
  }
  
  public void rollback() throws ServiceAccessException {
  }
  
  public void macroCopy(String sourceUri, String targetUri) throws ServiceAccessException, AccessDeniedException,
  ObjectNotFoundException, ObjectAlreadyExistsException {
    try {
      File fromFile = getFile(sourceUri);
      File toFile = getFile(targetUri);
      FileHelper.copyRec(fromFile, toFile);
      File propertyFile = getPropertyFile(sourceUri);
      File destPropertyFile = getPropertyFile(targetUri);
      if (propertyFile.exists()) {
        FileHelper.copy(propertyFile, destPropertyFile);
      }
      File lockFile = getLockFile(sourceUri);
      File destLockFile = getLockFile(targetUri);
      if (lockFile.exists()) {
        FileHelper.copy(propertyFile, destPropertyFile);
      }
    } catch (IOException e) {
      throw new ServiceAccessException(service, e);
    } catch (SecurityException e) {
      throw new AccessDeniedException(targetUri, e.getMessage(), "/actions/write");
    }
  }
  
  public void macroMove(String sourceUri, String targetUri) throws ServiceAccessException, AccessDeniedException,
  ObjectNotFoundException, ObjectAlreadyExistsException {
    try {
      File fromFile = getFile(sourceUri);
      File toFile = getFile(targetUri);
      fromFile.renameTo(toFile);
      // FileHelper.moveRec(fromFile, toFile);
      File propertyFile = getPropertyFile(sourceUri);
      File destPropertyFile = getPropertyFile(targetUri);
      if (propertyFile.exists()) {
        propertyFile.renameTo(destPropertyFile);
      }
      File lockFile = getLockFile(sourceUri);
      File destLockFile = getLockFile(targetUri);
      if (lockFile.exists()) {
        lockFile.renameTo(destLockFile);
      }
    } catch (SecurityException e) {
      throw new AccessDeniedException(targetUri, e.getMessage(), "/actions/write");
    }
  }
  
  public void macroDelete(String targetUri) throws ServiceAccessException, AccessDeniedException,
  ObjectNotFoundException {
    try {
      File file = getFile(targetUri);
      FileHelper.removeRec(file);
      File propertyFile = getPropertyFile(targetUri);
      if (propertyFile.exists()) {
        propertyFile.delete();
      }    
      File lockFile = getLockFile(targetUri);
      if (lockFile.exists()) {
        lockFile.delete();
      }    
    } catch (SecurityException e) {
      throw new AccessDeniedException(targetUri, e.getMessage(), "/actions/write");
    }
  }
  
  
  public boolean objectExists(String uri) throws ServiceAccessException, AccessDeniedException {
    try {   
      getRequstAndSession();
      if (webdavOperationManager != null){
        if(MOVE_METHED_NAME.equals(request.getMethod())){
          parseRequest();
          if(sourceUri.length() > 0&&destinationUri.length()>0){
            if(uri.indexOf(sourceUri) != -1 ){
              return true;    
            }
          }
        }else if(COPY_METHED_NAME.equals( request.getMethod() )){
          parseRequest();
          if(sourceUri.length() > 0&&destinationUri.length()>0){
            if(!uri.equals(destinationUri) && uri.indexOf(destinationUri) != -1 ){
              return true;    
            }
          }
        }                
        return webdavOperationManager.objectExists(uri);        
      }
      return true;      
    } catch (SecurityException e) {
      log.error(e, e);
      throw new AccessDeniedException(uri, e.getMessage(), "read");
    }
    
  }
  
  public boolean isFolder(String uri) throws ServiceAccessException, AccessDeniedException {
    try {
      getRequstAndSession();
      if(webdavOperationManager!=null){
        return webdavOperationManager.isFolder(uri);
      }
      return false;       
    } catch (Exception e) {
      log.error(e, e);
      throw new AccessDeniedException(uri, e.getMessage(), "read");            
    }
  }
  
  public boolean isResource(String uri) throws ServiceAccessException, AccessDeniedException {
    return true;
  }
  
  public void createFolder(String folderUri) throws ServiceAccessException, AccessDeniedException,
  ObjectAlreadyExistsException {       
    try {    
      getRequstAndSession();
      if(webdavOperationManager==null){   return;     }
      decodeMappingedUrl();
      //the createFolder not need execute twice at copy or move method
      if(request.getSession().getAttribute("methodExecCount") != null &&
          ((Integer)request.getSession().getAttribute("methodExecCount")).intValue() == 1){
        request.getSession().setAttribute("methodExecCount",null);                    
        return;
      }
      if(MOVE_METHED_NAME.equals(request.getMethod())){          
        if(sourceUri.length() > 0&&destinationUri.length()>0){
          String sourceFolder= sourceUri.substring(0,sourceUri.lastIndexOf("/"));
          String destFolder=destinationUri.substring(0,destinationUri.lastIndexOf("/"));
          if(!sourceFolder.equals(destFolder)){//rename Operating not need check create right
            webdavOperationManager.checkCreateRight(folderUri, true);
          }
          webdavOperationManager.moveObject(sourceUri,destinationUri);
        }
      }else if(COPY_METHED_NAME.equals(request.getMethod())){
        if(sourceUri.length() > 0&&destinationUri.length()>0){
          if(!folderUri.equals(destinationUri) && folderUri.indexOf(destinationUri) != -1 ){
            return ;    
          }
          webdavOperationManager.checkCreateRight(folderUri, true);
          webdavOperationManager.copyObject(sourceUri,destinationUri);
        }  
      }else{
        webdavOperationManager.checkCreateRight(folderUri, true);
        webdavOperationManager.createFolder(folderUri);
      }                
    } catch (SecurityException e) {
      if(MOVE_METHED_NAME.equals(request.getMethod()) || COPY_METHED_NAME.equals(request.getMethod())){
        if(request.getSession().getAttribute("methodExecCount") == null ){
          request.getSession().setAttribute("methodExecCount",new Integer(1));
        }
      }     
      log.error(e, e);
      throw new AccessDeniedException(folderUri, e.getMessage(), "create");
    } catch (Exception e) {
      if(MOVE_METHED_NAME.equals(request.getMethod()) || COPY_METHED_NAME.equals(request.getMethod())){
        if(request.getSession().getAttribute("methodExecCount") == null ){
          request.getSession().setAttribute("methodExecCount",new Integer(1));
        }
      }                 
      log.error(e, e);
      throw new AccessDeniedException(folderUri, e.getMessage(), "create");
    }
  }
  
  public String[] getChildrenNames(String folderUri) throws ServiceAccessException, AccessDeniedException,
  ObjectNotFoundException {
    try {
      getRequstAndSession();            
      String[] childrenNames = new String[0];
      if (webdavOperationManager != null){
        childrenNames = webdavOperationManager.getChildrenNames(folderUri);
      }
      return childrenNames;
      
    } catch (SecurityException e) {
      log.error(e, e);
      throw new AccessDeniedException(folderUri, e.getMessage(), "read");        
    } catch (Exception e) {
      log.error(e, e);
      throw new AccessDeniedException(folderUri, e.getMessage(), "read");
    }
    
  }
  
  public void createResource(String resourceUri) throws ServiceAccessException, AccessDeniedException,
  ObjectAlreadyExistsException {
  }
  
  public void setResourceContent(String resourceUri, InputStream content, String contentType, String characterEncoding) throws ServiceAccessException,
  AccessDeniedException, ObjectNotFoundException {
    try {
      getRequstAndSession(); 
      if(webdavOperationManager==null){   return;     }
      decodeMappingedUrl();
  
      if(MOVE_METHED_NAME.equals(request.getMethod())){
         if(sourceUri.length() > 0&&destinationUri.length()>0){  
           String sourceFolder= sourceUri.substring(0,sourceUri.lastIndexOf("/"));
           String destFolder=destinationUri.substring(0,destinationUri.lastIndexOf("/"));
           if(!sourceFolder.equals(destFolder)){//rename Operating not need check create right
             webdavOperationManager.checkCreateRight(resourceUri, false);
           }
           webdavOperationManager.moveObject(sourceUri,destinationUri);
         }
      }else if(COPY_METHED_NAME.equals(request.getMethod())){
         if(sourceUri.length() > 0&&destinationUri.length()>0){
              // if copy folder has some children ,webdav will conitun copy this children ,but at dms is already
              // do this opareat,so if copy this folder's children don't do something.
           if(!resourceUri.equals(destinationUri) && resourceUri.indexOf(destinationUri) != -1 ){
               return;    
            }
           webdavOperationManager.checkCreateRight(resourceUri, false);
           webdavOperationManager.copyObject(sourceUri,destinationUri);
         }                             
      }else{
         webdavOperationManager.checkCreateRight(resourceUri, false);
         webdavOperationManager.setResourceContent(resourceUri.toString(), content , contentType,
             characterEncoding,new Integer(request.getContentLength()),request.getMethod());
      } 
    }catch (SecurityException e) {
      if(MOVE_METHED_NAME.equals(request.getMethod()) || COPY_METHED_NAME.equals(request.getMethod())){
        if(request.getSession().getAttribute("resourceMethodExecCount") == null ){
          request.getSession().setAttribute("resourceMethodExecCount",new Integer(1));
        }
      }                 
      throw new AccessDeniedException(resourceUri, e.getMessage(), "setResource");
    }catch(SlideException e){                
      log.error(e, e); 
      throw new ObjectNotFoundException(resourceUri);  
    }finally{
      try{
        content.close();          
      }catch(Exception e){
        log.error(e, e);
      }
    }
  }
  
  public long getResourceLength(String resourceUri) throws ServiceAccessException, AccessDeniedException,
  ObjectNotFoundException {        
    long resourceLength = 0;        
    try {
      getRequstAndSession();            
      if(webdavOperationManager!=null){
        resourceLength = webdavOperationManager.getResourceLength(resourceUri,request.getMethod());
      }
    } catch (SecurityException e) {
      log.error(e, e);
      throw new AccessDeniedException(resourceUri, e.getMessage(), "create");
    }        
    return resourceLength;
  }
  
  public InputStream getResourceContent(String resourceUri) throws ServiceAccessException, AccessDeniedException,
  ObjectNotFoundException {
    InputStream in=null;
    try {
      if(WebdavOperationManager.DMS_WEBDAV_ROOT_FOLDER_URL.equals(resourceUri)){
        File file = getFile(resourceUri);
        if (!file.exists()) {
          throw new ObjectNotFoundException(resourceUri);
        }
        try {
          in = new BufferedInputStream(new FileInputStream(file));
        } catch (FileNotFoundException e) {
          throw new ObjectNotFoundException(resourceUri);
        }            
      }else{
        getRequstAndSession();
        if(webdavOperationManager!=null){
          in=webdavOperationManager.getResourceContent(resourceUri,request.getMethod());
        }
      }  
    } catch (SecurityException e) {
      log.error(e, e);
      throw new AccessDeniedException(resourceUri, e.getMessage(), "read");
    }
    return in;
  }
  
  public void removeObject(String uri) throws ServiceAccessException, AccessDeniedException, ObjectNotFoundException {
    try {
      getRequstAndSession();
      if(webdavOperationManager!=null && !MOVE_METHED_NAME.equals(request.getMethod())){
        webdavOperationManager.removeObject(uri);
      }
    } catch (SecurityException e) {
      log.error(e, e);
      throw new AccessDeniedException(uri, e.getMessage(), "delete");
    }       
  }
  
  public Date getLastModified(String uri) throws ServiceAccessException, AccessDeniedException,
  ObjectNotFoundException {
    Date lastDt=new Date();
    try {
      getRequstAndSession();
      if(webdavOperationManager!=null){
        lastDt= webdavOperationManager.getLastModified(uri);
      }   
    } catch (Exception e) {
      log.error(e, e);
      throw new AccessDeniedException(uri, e.getMessage(), "read");            
    }
    return lastDt;
  }
  
  public Date getCreationDate(String uri) throws ServiceAccessException, AccessDeniedException,
  ObjectNotFoundException {
    // XXX we do not have this information
    return getLastModified(uri);
  }
  
  public Map getProperties(String uri) throws ServiceAccessException, AccessDeniedException {
    File file = getPropertyFile(uri);
    if (!file.exists()) {
      return null;
    }
    return readProperties(file);
  }
  
  public void setProperties(String uri, Map properties) throws ServiceAccessException, AccessDeniedException {
    /*        
     File file = getPropertyFile(uri);
     assureCreated(file, uri);
     Properties props = new Properties();
     props.putAll(properties);
     saveProperties(file, props, "WebDAV properties");
     */        
  }
  
  public void addOrUpdateProperty(String uri, String name, String value) throws ServiceAccessException,        
  AccessDeniedException, ObjectNotFoundException {        
  }
  
  public void removeProperty(String uri, String name) throws ServiceAccessException, AccessDeniedException,
  ObjectNotFoundException {
  }
  
  public void lockObject(String uri, String lockId, String subject, Date expiration, boolean exclusive,
      boolean inheritable) throws ServiceAccessException, AccessDeniedException {
    
//  File file = getLockFile(uri);
//  assureCreated(file, uri);
    /*        
     Properties properties = readProperties(file);
     String lockString = expiration.getTime() + "|" + String.valueOf(exclusive) + "|" + String.valueOf(inheritable)
     + "|" + subject;
     properties.setProperty(lockId, lockString);
     saveProperties(file, properties, "WebDAV locks");
     */        
  }
  
  public void unlockObject(String uri, String lockId) throws ServiceAccessException, AccessDeniedException {
    File file = getLockFile(uri);
    if (!file.exists()) {
      throw new ServiceAccessException(service, "There nothing to unlock for " + uri);
    }
    Properties properties = readProperties(file);
    properties.remove(lockId);
    // do a special trick and remove the lock file when there are no more
    // locks
    if (properties.size() != 0) {
      saveProperties(file, properties, "WebDAV locks");
    } else {
      if (!file.delete()) {
        throw new ServiceAccessException(service, "Could not delete lock file for " + uri);
      }
    }
  }
  
  public Lock[] getLockInfo(String uri) throws ServiceAccessException, AccessDeniedException {
    File file = getLockFile(uri);
    if (!file.exists()) {
      return null;
    }
    Properties properties = readProperties(file);
    List locks = new ArrayList();
    Enumeration propNames = properties.propertyNames();
    while (propNames.hasMoreElements()) {
      String id = (String) propNames.nextElement();
      String value = properties.getProperty(id);
      if (value == null) {
        throw new ServiceAccessException(service, "Invalid lockId " + id);
      }
      StringTokenizer tokenizer = new StringTokenizer(value, "|");
      int tokens = tokenizer.countTokens();
      if (tokens != 4) {
        throw new ServiceAccessException(service, "Invalid lock information for lockId " + id);
      }
      String dateString = tokenizer.nextToken();
      String exclusiveString = tokenizer.nextToken();
      String inheritableString = tokenizer.nextToken();
      String subject = tokenizer.nextToken();
      Date date = new Date(Long.valueOf(dateString).longValue());
      boolean exclusive = Boolean.valueOf(exclusiveString).booleanValue();
      boolean inheritable = Boolean.valueOf(inheritableString).booleanValue();
      Lock lock = new SimpleLock(id, exclusive, inheritable, date, subject);
      locks.add(lock);
    }
    Lock[] lockArray = new Lock[locks.size()];
    lockArray = (Lock[]) locks.toArray(lockArray);
    return lockArray;
  }
  
  protected File getFile(String uri) {
    File file = new File(root, uri);
    return file;
  }
  
  protected File getPropertyFile(String uri) {
    String dir;
    String name;
    int lastSlash = uri.lastIndexOf('/');
    if (lastSlash != -1) {
      dir = uri.substring(0, lastSlash + 1);
      name = uri.substring(lastSlash + 1);
    } else {
      dir = "";
      name = uri;
    }
    String path = dir + PROPERTY_FILE_PREFIX + name;
    File file = new File(root, path);
    return file;
  }
  
  protected boolean isPropertyFilename(String uri) {
    
    return uri.startsWith(PROPERTY_FILE_PREFIX);
  }
  
  protected File getLockFile(String uri) {
    
    File file = new File(root, uri + LOCK_FILE_EXTENSION);
    return file;
  }
  
  protected boolean isLockFilename(String uri) {
    
    return uri.endsWith(LOCK_FILE_EXTENSION);
  }
  
  protected void assureCreated(File file, String uri) throws ServiceAccessException {
    
    if (!file.exists()) {
      try {
        if (!file.createNewFile()) {
          throw new ServiceAccessException(service, "Can not create file " + uri);
        }
      } catch (IOException e) {
        throw new ServiceAccessException(service, e);
      }
    }
  }
  
  protected String getLockEntry(String uri, String lockId) throws ServiceAccessException, ObjectNotFoundException {
    File file = getLockFile(uri);
    if (!file.exists()) {
      throw new ObjectNotFoundException(uri);
    }
    Properties properties = readProperties(file);
    String value = properties.getProperty(lockId);
    if (value == null) {
      throw new ServiceAccessException(service, "Invalid lockId " + lockId);
    }
    return value;
  }
  
  protected void saveProperties(File file, Properties properties, String header) throws ServiceAccessException {
    /*        
     OutputStream os = null;
     try {
     os = new BufferedOutputStream(new FileOutputStream(file));
     properties.store(os, header);
     } catch (FileNotFoundException e) {
     throw new ServiceAccessException(service, e);
     } catch (IOException e) {
     throw new ServiceAccessException(service, e);
     } finally {
     if (os != null)
     try {
     os.close();
     } catch (IOException e) {
     }
     }
     */        
  }
  
  protected Properties readProperties(File file) throws ServiceAccessException {
    InputStream is = null;
    try {
      is = new BufferedInputStream(new FileInputStream(file));
      Properties properties = new Properties();
      properties.load(is);
      return properties;
    } catch (FileNotFoundException e) {
      throw new ServiceAccessException(service, e);
    } catch (IOException e) {
      throw new ServiceAccessException(service, e);
    } finally {
      if (is != null) {
        try {
          is.close();
        } catch (IOException e) {
        }
      }
    }
  }
  
  /**
   * precondition: sourceUri != null
   */
  protected String parseUri(String uri,HttpServletRequest req) throws Exception {  // TODO: better name
    int protocolIndex = uri.indexOf("://");
    if (protocolIndex >= 0) {
      // if the Destination URL contains the protocol, we can safely
      // trim everything upto the first "/" character after "://"
      int firstSeparator =
        uri.indexOf("/", protocolIndex + 4);
      if (firstSeparator < 0) {
        uri = "/";
      } else {
        uri = uri.substring(firstSeparator);
      }
    } else {
      String hostName = req.getServerName();
      if ((hostName != null) && (uri.startsWith(hostName))) {
        uri = uri.substring(hostName.length());
      }
      
      int portIndex = uri.indexOf(":");
      if (portIndex >= 0) {
        uri = uri.substring(portIndex);
      }
      
      if (uri.startsWith(":")) {
        int firstSeparator = uri.indexOf("/");
        if (firstSeparator < 0) {
          uri = "/";
        } else {
          uri = uri.substring(firstSeparator);
        }
      }
    }
    
    // headers are "ISO-8859-1" encoded [not any more with TC 4.1.18
    // destinationUri = WebdavUtils.decodeURL(WebdavUtils.fixTomcatURL(destinationUri, "ISO-8859-1"));
//  uri = WebdavUtils.decodeURL(WebdavUtils.fixTomcatURL(uri, "ISO-8859-1"));
    //uri = WebdavUtils.decodeURL(uri);
    
    String contextPath = req.getContextPath();
    if ((contextPath != null) && (uri.startsWith(contextPath))) {
      uri = uri.substring(contextPath.length());
    }
    String pathInfo = req.getPathInfo();
    if (pathInfo != null) {
      String servletPath = req.getServletPath();
      if ((servletPath != null) && (uri.startsWith(servletPath))) {
        uri = uri.substring(servletPath.length());
      }
    }
    //uri = getConfig().getScope() + uri;
    return uri;
  }    
  
  /**
   * getSessionContainer
   *
   * @param request  The HTTP request
   * @return     The Session Container
   */
  public SessionContainer getSessionContainer(HttpServletRequest request) {
    SessionContainer ctx = (SessionContainer)request.getSession().getAttribute(GlobalConstant.SESSION_CONTAINER_KEY);
    if (ctx==null) {
      ctx = new SessionContainer();
      request.getSession().setAttribute(GlobalConstant.SESSION_CONTAINER_KEY, ctx);
    }
    return(ctx);
  }    
  
  public void getRequstAndSession(){
    this.request  = ActionContext.getActionContext().getRequest();
    this.response = ActionContext.getActionContext().getResponse();
    try{
      if(request!=null && request.getSession()!=null){        
        this.sessionCner=(SessionContainer)request.getSession().getAttribute(GlobalConstant.SESSION_CONTAINER_KEY);                     
        if(sessionCner != null){
          this.sessionUser = sessionCner.getUserRecord();
          webdavOperationManager = new WebdavOperationManager(sessionCner,null);
        }
      }
    }catch(Exception e){
      log.error(e, e);
    }
  }
  
  private static class SimpleLock implements Lock {
    
    public String id;
    
    public boolean exclusive;
    
    public boolean inheritable;
    
    public Date expirationDate;
    
    public String subject;
    
    public SimpleLock(String id, boolean exclusive, boolean inheritable, Date expirationDate, String subject) {
      this.id = id;
      this.exclusive = exclusive;
      this.inheritable = inheritable;
      this.expirationDate = expirationDate;
      this.subject = subject;
    }
    
    public boolean isExclusive() {
      return exclusive;
    }
    
    public Date getExpirationDate() {
      return expirationDate;
    }
    
    public String getId() {
      return id;
    }
    
    public boolean isInheritable() {
      return inheritable;
    }
    
    public String getSubject() {
      return subject;
    }
    
  }
  
  /**
   * Parse request.
   *
   * @exception
   */
  
  protected void parseRequest(){
    sourceUri = request.getPathInfo();        
    destinationUri = request.getHeader(H_DESTINATION);
    try{
      destinationUri = parseUri(destinationUri,request);
      sourceUri = parseUri(sourceUri,request);
      sourceUri = WebdavOperationManager.DMS_WEBDAV_ROOT_FOLDER_URL + sourceUri;
      destinationUri = WebdavOperationManager.DMS_WEBDAV_ROOT_FOLDER_URL + URLDecoder.decode(destinationUri,"UTF-8");        
    }catch (Exception e){
      log.error(e, e);        
    }
  }
  
  protected void decodeMappingedUrl(){
    try{
      sourceUri =   URLDecoder.decode(sourceUri, "UTF-8");
      destinationUri = URLDecoder.decode(destinationUri, "UTF-8");
    }catch (Exception e){
      log.error(e, e);       
    }
  }
  protected void decodeMappingedUrl22(){
    try{
      sourceUri =   URLDecoder.decode(sourceUri, "UTF-8");
      destinationUri = URLDecoder.decode(destinationUri, "UTF-8");
    }catch (Exception e){
      log.error(e, e);        
    }
  }
  
  private void printInfo(String infor){
    if(true){
      System.out.println(infor) ;
    }
  }  
}
